/**
 * 图片优化工具 - 减少图片数据量，提升传输效率
 */

const fs = require('fs');
const path = require('path');
const { createLogger } = require('../logger');

const logger = createLogger('image-optimizer');

class ImageOptimizer {
    constructor() {
        this.maxFileSize = 2 * 1024 * 1024; // 2MB
        this.compressionQuality = 0.8;
        this.maxDimensions = { width: 1024, height: 1024 };
    }

    /**
     * 优化图片数据
     * @param {string} imageData - base64图片数据或文件路径
     * @returns {Promise<string>} - 优化后的base64数据
     */
    async optimizeImage(imageData) {
        try {
            let imageBuffer;
            let originalFormat = 'png';

            // 处理输入数据
            if (fs.existsSync(imageData)) {
                // 文件路径
                imageBuffer = fs.readFileSync(imageData);
                originalFormat = path.extname(imageData).slice(1).toLowerCase();
            } else if (imageData.startsWith('data:image/')) {
                // Data URL格式
                const matches = imageData.match(/^data:image\/(\w+);base64,(.+)$/);
                if (matches) {
                    originalFormat = matches[1];
                    imageBuffer = Buffer.from(matches[2], 'base64');
                } else {
                    throw new Error('无效的data URL格式');
                }
            } else {
                // 纯base64字符串
                imageBuffer = Buffer.from(imageData, 'base64');
            }

            const originalSize = imageBuffer.length;
            logger.debug(`原始图片大小: ${(originalSize / 1024 / 1024).toFixed(2)}MB`);

            // 如果文件较小，直接返回
            if (originalSize <= this.maxFileSize) {
                logger.debug('图片大小在限制范围内，跳过压缩');
                return this.toDataUrl(imageBuffer, originalFormat);
            }

            // 尝试压缩图片
            const optimizedBuffer = await this.compressImage(imageBuffer, originalFormat);
            const optimizedSize = optimizedBuffer.length;

            logger.info(`图片优化完成: ${(originalSize / 1024 / 1024).toFixed(2)}MB -> ${(optimizedSize / 1024 / 1024).toFixed(2)}MB (压缩率: ${((1 - optimizedSize / originalSize) * 100).toFixed(1)}%)`);

            return this.toDataUrl(optimizedBuffer, originalFormat);

        } catch (error) {
            logger.warn('图片优化失败，使用原始数据:', error.message);
            return imageData;
        }
    }

    /**
     * 压缩图片
     * @param {Buffer} imageBuffer - 图片缓冲区
     * @param {string} format - 图片格式
     * @returns {Promise<Buffer>} - 压缩后的图片缓冲区
     */
    async compressImage(imageBuffer, format) {
        // 这里可以使用sharp或其他图片处理库
        // 由于依赖考虑，这里提供简单的降采样方案

        try {
            // 简单的降采样：通过减少图片数据来实现压缩
            // 实际项目中建议使用sharp库进行真正的图片压缩

            if (format === 'png') {
                // PNG压缩：移除元数据，使用更简单的压缩
                return this.simplePngCompression(imageBuffer);
            } else if (format === 'jpeg' || format === 'jpg') {
                // JPEG压缩：调整质量参数
                return this.simpleJpegCompression(imageBuffer);
            } else {
                // 其他格式，转换为JPEG以获得更好的压缩比
                return this.simpleJpegCompression(imageBuffer);
            }
        } catch (error) {
            logger.warn('图片压缩失败，使用原始数据:', error.message);
            return imageBuffer;
        }
    }

    /**
     * 简单的PNG压缩
     * @param {Buffer} buffer - PNG图片缓冲区
     * @returns {Buffer} - 压缩后的缓冲区
     */
    simplePngCompression(buffer) {
        // 移除PNG中的非必要数据块
        const signature = Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]);

        if (!buffer.slice(0, 8).equals(signature)) {
            return buffer; // 不是PNG文件
        }

        try {
            // 简单的压缩：保留关键数据块，移除元数据
            const chunks = this.parsePngChunks(buffer);
            const essentialChunks = chunks.filter(chunk =>
                ['IHDR', 'IDAT', 'IEND'].includes(chunk.type)
            );

            // 重新构建PNG
            const compressedBuffer = Buffer.concat([
                signature,
                ...essentialChunks.map(chunk => this.buildPngChunk(chunk))
            ]);

            return compressedBuffer;
        } catch (error) {
            return buffer;
        }
    }

    /**
     * 简单的JPEG压缩
     * @param {Buffer} buffer - JPEG图片缓冲区
     * @returns {Buffer} - 压缩后的缓冲区
     */
    simpleJpegCompression(buffer) {
        // JPEG压缩：移除EXIF和其他元数据
        try {
            // 查找SOF0标记（图像开始）
            const sof0Index = this.findJpegMarker(buffer, 0xFFC0);
            if (sof0Index === -1) {
                return buffer; // 不是有效的JPEG
            }

            // 移除JPEG头部元数据，保留图像数据
            const imageDataStart = this.findJpegMarker(buffer, 0xFFDA); // SOS标记
            if (imageDataStart === -1) {
                return buffer;
            }

            const headerLength = imageDataStart + 2; // 包括SOS标记
            const compressedBuffer = Buffer.concat([
                buffer.slice(0, 2), // JPEG SOI标记
                Buffer.from([0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01]), // 简化的JFIF标记
                buffer.slice(headerLength)
            ]);

            return compressedBuffer;
        } catch (error) {
            return buffer;
        }
    }

    /**
     * 解析PNG数据块
     * @param {Buffer} buffer - PNG缓冲区
     * @returns {Array} - 数据块数组
     */
    parsePngChunks(buffer) {
        const chunks = [];
        let offset = 8; // 跳过PNG签名

        while (offset < buffer.length) {
            if (offset + 8 > buffer.length) break;

            const length = buffer.readUInt32BE(offset);
            const type = buffer.slice(offset + 4, offset + 8).toString();
            const data = buffer.slice(offset + 8, offset + 8 + length);
            const crc = buffer.slice(offset + 8 + length, offset + 8 + length + 4);

            chunks.push({ type, data, crc });
            offset += 8 + length + 4;

            if (type === 'IEND') break;
        }

        return chunks;
    }

    /**
     * 构建PNG数据块
     * @param {Object} chunk - 数据块对象
     * @returns {Buffer} - 数据块缓冲区
     */
    buildPngChunk(chunk) {
        const length = Buffer.alloc(4);
        length.writeUInt32BE(chunk.data.length, 0);

        const type = Buffer.from(chunk.type);
        const crc = this.calculateCrc(Buffer.concat([type, chunk.data]));

        return Buffer.concat([length, type, chunk.data, crc]);
    }

    /**
     * 计算CRC32校验码
     * @param {Buffer} data - 数据缓冲区
     * @returns {Buffer} - CRC32校验码
     */
    calculateCrc(data) {
        // 简化的CRC32计算
        const crcTable = [];
        for (let i = 0; i < 256; i++) {
            let c = i;
            for (let j = 0; j < 8; j++) {
                c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
            }
            crcTable[i] = c;
        }

        let crc = 0xFFFFFFFF;
        for (let i = 0; i < data.length; i++) {
            crc = crcTable[(crc ^ data[i]) & 0xFF] ^ (crc >>> 8);
        }

        const result = Buffer.alloc(4);
        result.writeUInt32BE((crc ^ 0xFFFFFFFF) >>> 0, 0);
        return result;
    }

    /**
     * 查找JPEG标记
     * @param {Buffer} buffer - JPEG缓冲区
     * @param {number} marker - 标记值
     * @returns {number} - 标记位置，-1表示未找到
     */
    findJpegMarker(buffer, marker) {
        for (let i = 0; i < buffer.length - 1; i++) {
            if (buffer.readUInt16BE(i) === marker) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 转换为Data URL格式
     * @param {Buffer} buffer - 图片缓冲区
     * @param {string} format - 图片格式
     * @returns {string} - Data URL
     */
    toDataUrl(buffer, format) {
        const base64 = buffer.toString('base64');
        return `data:image/${format};base64,${base64}`;
    }

    /**
     * 获取图片信息
     * @param {string} imageData - 图片数据
     * @returns {Object} - 图片信息
     */
    getImageInfo(imageData) {
        try {
            let buffer;
            if (fs.existsSync(imageData)) {
                buffer = fs.readFileSync(imageData);
            } else if (imageData.startsWith('data:image/')) {
                const matches = imageData.match(/^data:image\/\w+;base64,(.+)$/);
                if (matches) {
                    buffer = Buffer.from(matches[1], 'base64');
                }
            } else {
                buffer = Buffer.from(imageData, 'base64');
            }

            return {
                size: buffer.length,
                sizeMB: (buffer.length / 1024 / 1024).toFixed(2),
                format: this.detectImageFormat(buffer)
            };
        } catch (error) {
            return { error: error.message };
        }
    }

    /**
     * 检测图片格式
     * @param {Buffer} buffer - 图片缓冲区
     * @returns {string} - 图片格式
     */
    detectImageFormat(buffer) {
        if (buffer.length < 4) return 'unknown';

        // PNG
        if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4E && buffer[3] === 0x47) {
            return 'png';
        }

        // JPEG
        if (buffer[0] === 0xFF && buffer[1] === 0xD8 && buffer[2] === 0xFF) {
            return 'jpeg';
        }

        // GIF
        if (buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46) {
            return 'gif';
        }

        // WebP
        if (buffer[8] === 0x57 && buffer[9] === 0x45 && buffer[10] === 0x42 && buffer[11] === 0x50) {
            return 'webp';
        }

        return 'unknown';
    }
}

module.exports = ImageOptimizer;